// =============================================
// FD Fluid UV Distort
// Made by Ubik and Claude 2026
// =============================================
// Deforms video input using two layers of
// rotating sin/cos wave fields. Creates a
// fluid, melting, psychedelic look.
// Connect video source to video in 1.
//
// Tiling: when distortion pushes UVs outside
// the image edge, the image tiles seamlessly
// instead of clamping to the border color.
// =============================================

// ISADORA_PLUGIN_DESC("Fluid UV Distort - warps video input with two layers of rotating sin/cos wave fields. Tiling fills areas outside edges. Psychedelic melting effect.")

// ISADORA_FLOAT_PARAM(warp_strength, wstr, 0.0, 0.5, 0.04, "How strongly the image is deformed. 0 = no effect, 0.5 = extreme.")
// ISADORA_FLOAT_PARAM(warp_speed, wspd, 0.0, 3.0, 0.4, "How fast the wave motion flows.")
// ISADORA_FLOAT_PARAM(warp_frequency, wfrq, 0.5, 12.0, 3.0, "Density of the waves. Low = large soft waves, high = fine chaotic detail.")
// ISADORA_FLOAT_PARAM(warp_rotation, wrot, 0.0, 1.0, 0.12, "How fast the wave field slowly rotates. 0 = static direction, 1 = fast rotation.")

uniform float warp_strength;
uniform float warp_speed;
uniform float warp_frequency;
uniform float warp_rotation;
uniform float iTime;
uniform vec3 iResolution;
uniform sampler2D tex0;

void main()
{
    vec2 uv = gl_FragCoord.xy / iResolution.xy;
    float t = iTime * warp_speed;
    float rot = iTime * warp_rotation * 0.5;

    // Build a slowly rotating coordinate system
    float cosR = cos(rot);
    float sinR = sin(rot);
    vec2 ruv = vec2(
        cosR * (uv.x - 0.5) - sinR * (uv.y - 0.5),
        sinR * (uv.x - 0.5) + cosR * (uv.y - 0.5)
    );

    float f = warp_frequency;

    // Layer 1: primary wave field
    float wx1 = sin(ruv.y * f + t) * cos(ruv.x * f * 0.7 + t * 0.8);
    float wy1 = cos(ruv.x * f + t * 1.1) * sin(ruv.y * f * 0.9 - t * 0.6);

    // Layer 2: secondary wave field at different phase for organic feel
    float wx2 = sin(ruv.y * f * 1.3 - t * 0.7 + 1.5) * cos(ruv.x * f * 0.5 + t * 0.5);
    float wy2 = cos(ruv.x * f * 1.1 + t * 0.9 + 0.8) * sin(ruv.y * f * 0.8 - t * 1.2);

    vec2 warp = vec2(wx1 + wx2, wy1 + wy2) * 0.5 * warp_strength;
    vec2 distorted_uv = uv + warp;

    // Tile: fract() wraps UVs so areas outside edges show tiled copies
    // This avoids border-color smearing at the edges during heavy warping
    distorted_uv = fract(distorted_uv);

    vec4 color = texture2D(tex0, distorted_uv);
    gl_FragColor = vec4(color.rgb, color.a);
}
